/**
 * 防抖函数（常用于input框搜索情况）
 * @param {*} func 
 * @param {*} delay 
 * @param {*} immediate 
 * @returns 
 */
export function debounce(func, delay, immediate = true) {
  let timer = null
  return function(args) {
    let _this = this
    if (timer) {
      clearTimeout(timer)
    }
    if (immediate) {
      let now = !timer
      timer = setTimeout(() => {
        timer = null
      }, delay)
      now && func.call(_this, args)
    } else {
      timer = setTimeout(() => {
        timer = null
        func.call(_this, args)
      }, delay)
    }
  }
 }

/**
 * 节流函数（常用于onresize, onmouseover情况）
 * @param {*} func 
 * @param {*} delay 
 * @param {*} immediate 
 * @returns 
 */
export function throttle(func, delay, immediate = true) {
  let timer = null
  return function (args) {
    let _this = this
    if (!timer) {
      if (immediate) {
        func.call(_this, args)
        timer = setTimeout(() => {
          timer = null
        }, delay)
      } else {
        timer = setTimeout(() => {
          func.call(_this, args)
          timer = null
        }, delay)
      }
    }
  }
}

/**
 * 文件大小单位转换
 * @param size
 * @returns
 */
export function getfilesize(size) {
  if (!size) {
    return '';
  }
  const num = 1024.00;
  if (size < num) {
    return size + 'B';
  } else if (size < Math.pow(num, 2)) {
    return (size / num).toFixed(2) + 'K'; // kb
  } else if (size < Math.pow(num, 3)) {
    return (size / Math.pow(num, 2)).toFixed(2) + 'M'; // M
  } else if (size < Math.pow(num, 4)) {
    return (size / Math.pow(num, 3)).toFixed(2) + 'G'; // G
  } else {
    return (size / Math.pow(num, 4)).toFixed(2) + 'T'; // T
  }
}

/**
 * 深层级对象根据路径字符串赋值
 * @param {*} obj 对象
 * @param {*} path 路径字符串(由小数点分割)
 * @param {*} value 赋值
 */
export function deepSetValue(obj, path, value) {
  if (!path) {
    return
  }
  const keys = path.split('.');
  if (keys.length === 1) {
    obj[keys[0]] = value
  } else {
    const [curPath, ...nextPath] = keys
    if (!obj[curPath]) {
      obj[curPath] = {}
    }
    deepSetValue(obj[curPath], nextPath.join('.'), value)
  }
}

// 举例: deepSetValue({}, 'a.b', 'hello world') => {a: {b: 'hello world'}}

/**
 * 深层级对象根据路径字符串取值
 * @param {*} obj 对象
 * @param {*} path 路径字符串(由小数点分割)
 */
export function deepGetValue(obj, path) {
  let result = JSON.parse(JSON.stringify(obj))
  if (!path) {
    return result
  }
  const keys = path.split('.');
  for (const key of keys) {
    // 分区值为0的情况
    if (!result || (!result[key] && result[key] !== 0)) {
      return
    }
    result = result[key];
  }
  return result
}

// 举例: deepGetValue({a: {b: 'hello world'}}, 'a.b') => 'hello world'

/**
 * *深拷贝
 * @peram deep
 *   true => 深拷贝,
 *   vue => 适用于VUE的深拷贝(删除原对象多余的数组),
 *   'add' => 只增加新属性的深拷贝,
 *   'reader' => 只改变已有属性的深拷贝
 *   'reader-arr' => 只改变已有属性的深拷贝, 可添加数组
 * ps: 被拷贝属性为 undefined时跳过
 * @param  {...any} rest
 * @return 目标对象
 */
export function clone(deep, ...rest) {
  if (deep !== true && typeof deep === 'object') { // simple copy
    return Object.assign(deep, ...rest);
  } else if (rest.every(v => typeof v === 'object')) { // deep copy
    const [own, ...copy] = rest;
    deep === 'add' && copy.reverse();
    copy.forEach(obj => {
      const isArray = Object.prototype.toString.call(obj) === '[object Array]' && !!own.splice;
      if (deep === 'vue' && isArray && obj.length < 1) own.splice(0, own.length);
      for (const key in obj) {
        if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;// ignore prototype
        const ownVal = own[key];
        const copyVal = obj[key];
        const hasProperty = (deep === 'reader-arr' && !!own.splice) || Object.prototype.hasOwnProperty.call(own, key);
        const isLimit = !(deep === 'add' && hasProperty) && !((deep === 'reader' || deep === 'reader-arr') && !hasProperty);
        if (typeof copyVal === 'object' && copyVal !== null) { // Copy the arrays, objects
          const constCopy = copyVal.constructor;
          const constOwn = (ownVal !== undefined && ownVal !== null) && ownVal.constructor;
          if (constOwn === constCopy) {
            clone(deep, ownVal, copyVal);
            if (isArray) {
              if (deep === 'vue' && key * 1 === obj.length - 1) {
                own.splice(obj.length);
              }
            }
          } else if (isLimit) { // ownVal === undefined or null
            if (isArray) {
              own.splice(key, 1, clone((deep === 'reader' || deep === 'reader-arr') && true || deep, constCopy === Array ? [] : {}, copyVal));
              if (deep === 'vue' && key * 1 === obj.length - 1) {
                own.splice(obj.length);
                break;
              }
            } else {
              clone((deep === 'reader' || deep === 'reader-arr') && true || deep, own[key] = constCopy === Array ? [] : {}, copyVal);
            }
          }
        } else if (isLimit && copyVal !== undefined) {
          if (isArray) {
            own.splice(key, 1, copyVal);
            if (deep === 'vue' && key * 1 === obj.length - 1) {
              own.splice(obj.length);
            }
          } else {
            own[key] = copyVal;
          }
        }
      }
    });
    return own;
  }
}

// let obj1 = { a: { b: 1, c: 1 } };
// let obj2 = { a: { b: 2 } };
// let obj3 = {};
// 举例: clone(true, obj3, obj1, obj2) => {a: {b: 2, c: 1}}
